

#ifndef _PHYSM_H
#  define _PHYSM_H

#  include <config.h>
#  include <memory.h>
#  include <llist.h>

#  ifdef _PHYSM_PROC_x86_64
#    include <fast_vec.h>
#  else
#    include <vector.h>
#  endif
#  include <stdlib.h>
#  include <string.h>
#  include <pthread.h>

#  define PHYSM_LOCK(data) pthread_mutex_lock(&data->lock)
#  define PHYSM_UNLOCK(data) pthread_mutex_unlock(&data->lock)

/* These are the important structs for the simulator. */

typedef struct _physm_body {

  /* Useful things */
  long id;
  pthread_mutex_t lock;
  
  /* Body data */
  double width; 
  double mass;
  vm_vector loc;
  vm_vector vel;

  vm_vector force;
  vm_vector accel;

} physm_body_t;

typedef struct _physm_world {

  pthread_mutex_t lock;
 
  /* World data. */
  double tau;
  double t;
  long step;
  llist_t *bodies;

} physm_world_t;

#  define PHYSM_ALLOC_BODY() (physm_body_t *) malloc(sizeof(physm_body_t)); \
  _physm_mem_add(sizeof(physm_body_t))
#  define PHYSM_ALLOC_WORLD() (physm_world_t *) malloc(sizeof(physm_world_t)); \
  _physm_mem_add(sizeof(physm_world_t))
#  define PHYSM_ALLOC_LLIST() (llist_t *) malloc(sizeof(llist_t));	\
  _physm_mem_add(sizeof(llist_t))

 /* Some functions... */
void          physm_body_init(physm_body_t *);
void         _physm_body_print(physm_body_t *);
int           physm_world_init(physm_world_t *, char *, double);
int           physm_simulate(physm_world_t *, long, int);
int          _physm_do_sim(physm_world_t *, long, int);

/* Wrappers for the list calls (keep track of memory allocation) */
physm_body_t *physm_llist_add(llist_t *, physm_body_t *);
physm_body_t *physm_llist_get(llist_t *, int);
physm_body_t *physm_llist_del(llist_t *, int);
int           physm_llist_len(llist_t *);
void          physm_llist_init(llist_t *);

/* Some of the functions for doing the sim. */
int           physm_simulate(physm_world_t *, long, int);
int          _physm_thread_run_calc_force(physm_world_t *, int);
int          _physm_thread_run_reloc_bodies(physm_world_t *,  int);
int          _physm_math_calc_force(physm_world_t *, physm_body_t *);
void         _physm_math_reloc_body(physm_world_t *, physm_body_t *);

/* Que functions  and data structures */

typedef struct _physm_que {

  pthread_mutex_t lock;
  llist_t *list;
  int offset;
  int size;

} physm_que_t;

void          physm_que_init(physm_que_t *, llist_t *);
void          physm_que_add(physm_que_t *, physm_body_t *);
void          physm_que_position(physm_que_t *, int);
void          physm_que_reset(physm_que_t *);
physm_body_t *physm_que_next(physm_que_t *);

#endif
